`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/26 14:35:22
// Design Name: 
// Module Name: rv_decode
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module rv_decode(
    input CLK,input RST,
    
    //IR --> decode
    input [31:0] INST,
    //ISSUE-->Decode
    input [1:0] ISSUE_THREAD_ID,
    input [31:0] ISSUE_PC,
    input [1:0] WRITED_THREAD_ID,
    input [4:0] RD_WRITED_INDEX,
    input [31:0] RD_WRITED_VALUE,
    
    //Decode-->EX inst
    output [4:0] INST_TYPE,
    output [2:0] FUNC3,
    output [2:0] ALU_FUNC3,
    output INST30,
    output [4:0] RS1_INDEX,
    output [4:0] RS2_INDEX,

    //Decode -->rd_index and rd_src chain
    output [4:0] RD_INDEX,
    output [1:0] RD_SRC,//00 ALU,CSR;01 DMEM;10,11 32'b0

    //Regfile --> decode
    input [4:0] REGF_RS1_INDEX,
    input [4:0] REGF_RS2_INDEX,
    input [31:0] REGF_RS1_VALUE,
    input [31:0] REGF_RS2_VALUE,

    //Decode-->EX Data
    output [31:0] DEC_RS1_VALUE,
    output [31:0] DEC_RS2_VALUE,
    output [31:0] IMM32
    );

    wire [4:0] inst_type;
    assign inst_type=INST[6:2];
    regw #(.WIDTH(5)) INST_TYPE_REG(CLK,RST,1'b1,inst_type,INST_TYPE);

    wire [2:0] func3;
    assign func3=INST[14:12];
    regw #(.WIDTH(3)) FUNC3_REG(CLK,RST,1'b1,func3,FUNC3);

    wire [31:0] imm32_inst;
    imm_decoder IMM_DECODER(INST[31:2],imm32_inst);
    
    reg [2:0] alu_func3;
    reg inst30;
    reg [31:0] imm32;
    reg [31:0] rs1_value,rs2_value;
    wire [31:0] regf_rs1_value,regf_rs2_value;
    
    assign regf_rs1_value = WRITED_THREAD_ID==ISSUE_THREAD_ID && RD_WRITED_INDEX==REGF_RS1_INDEX?RD_WRITED_VALUE:REGF_RS1_VALUE;
    assign regf_rs2_value = WRITED_THREAD_ID==ISSUE_THREAD_ID && RD_WRITED_INDEX==REGF_RS2_INDEX?RD_WRITED_VALUE:REGF_RS2_VALUE;
    
    always @(*) begin
        case(inst_type)
            `INST_LOAD,`INST_STORE:begin  //rs1+imm32
                alu_func3=3'b000;inst30=1'b0;imm32=imm32_inst;rs1_value=regf_rs1_value;
                end
            `INST_OP_IMM: begin  //rs1 op imm32
                alu_func3=INST[14:12];imm32=imm32_inst;rs1_value=regf_rs1_value;
                if(INST[14:12]==3'b101) inst30=INST[30];
                else inst30=1'b0;
                end
            `INST_OP: begin  //rs1+rs2
                alu_func3=INST[14:12];inst30=INST[30];imm32=32'b0;rs1_value=regf_rs1_value; 
                end
            `INST_AUIPC,`INST_LUI:  begin  //pc(0)+imm32_inst
                alu_func3=3'b000;inst30=1'b0;imm32=imm32_inst;rs1_value=32'b0;
                end
            `INST_BRANCH: begin  //rs1<rs2 or signed(rs1)<signed(rs2)
                if(INST[13]==1'b1) alu_func3=3'b011;//unsigned compare
                else alu_func3=3'b010; //signed compare
                inst30=1'b0;imm32=imm32_inst;rs1_value=regf_rs1_value;
                end
            `INST_JALR,`INST_JAL: begin//PC+4
                alu_func3=3'b000;inst30=1'b0;imm32=32'd4;rs1_value=32'b0;
                end
            `INST_SYSTEM: begin//
                alu_func3=3'b000;inst30=1'b0;imm32=imm32_inst;rs1_value=regf_rs1_value;
                end
            default:begin
                alu_func3=3'b000;inst30=1'b0;imm32=32'b0;rs1_value=32'b0;
                end
        endcase
    end
    
    regw #(.WIDTH(1)) INST30_REG(CLK,RST,1'b1,inst30,INST30);
    regw #(.WIDTH(3)) ALU_FUNC3_REG(CLK,RST,1'b1,alu_func3,ALU_FUNC3);
    regw #(.WIDTH(32)) IMM32_VALUE_REG(CLK,RST,1'b1,imm32,IMM32);
    //Reg file data
    regw #(.WIDTH(32)) R1_VALUE_REG(CLK,RST,1'b1,rs1_value,DEC_RS1_VALUE);
    regw #(.WIDTH(32)) R2_VALUE_REG(CLK,RST,1'b1,regf_rs2_value,DEC_RS2_VALUE);

    regw #(.WIDTH(5)) RS1_INDEX_REG(CLK,RST,1'b1,INST[19:15],RS1_INDEX);
    regw #(.WIDTH(5)) RS2_INDEX_REG(CLK,RST,1'b1,INST[24:20],RS2_INDEX);

    reg [1:0] rd_src;
    always @(*) begin
        case(inst_type)
            `INST_LOAD: rd_src=2'b01;
            `INST_STORE,`INST_BRANCH,`INST_JALR,`INST_JAL: rd_src=2'b11;
            `INST_OP_IMM,`INST_OP,`INST_AUIPC,`INST_LUI,`INST_SYSTEM: rd_src=2'b00;
            default:rd_src=2'b11;
        endcase
    end
    regw #(.WIDTH(2)) RD_SRC_REG(CLK,RST,1'b1,rd_src,RD_SRC);

    reg [4:0] rd_index;
    always @(*) begin
        case(inst_type)
            `INST_STORE,`INST_BRANCH:  rd_index=5'b0;
            `INST_OP_IMM,`INST_OP,`INST_AUIPC,`INST_LOAD,
            `INST_LUI,`INST_JALR,`INST_JAL,`INST_SYSTEM: rd_index=INST[11:7];
            default:rd_index=5'b0;
        endcase
    end
    regw #(.WIDTH(5)) RD_INDEX_REG(CLK,RST,1'b1,rd_index,RD_INDEX);
endmodule

module imm_decoder(input [29:0] instr_in,
                   output reg [31:0] imm_out);


always @(*) begin
	case(instr_in[4:0])
		5'b01101 : imm_out = { instr_in[29:10], 12'b0 }; // U-type
		5'b00101 : imm_out = { instr_in[29:10], 12'b0 }; // U-type
		5'b11011 : imm_out = { {12{ instr_in[29] }}, instr_in[17:10], instr_in[18], instr_in[28:23], instr_in[22:19], 1'b0 };// J-type
		5'b11001 : imm_out = { {21{ instr_in[29] }}, instr_in[28:23], instr_in[22:19], instr_in[18] };// I-type
		5'b00000 : imm_out = { {21{ instr_in[29] }}, instr_in[28:23], instr_in[22:19], instr_in[18] };// I-type
		5'b00100 : imm_out = { {21{ instr_in[29] }}, instr_in[28:23], instr_in[22:19], instr_in[18] };// I-type
		5'b11000 : imm_out = { {20{ instr_in[29] }}, instr_in[5], instr_in[28:23], instr_in[9:6], 1'b0 };// B-type
		5'b01000 : imm_out = { {21{ instr_in[29] }}, instr_in[28:23], instr_in[9:6], instr_in[5] };// S-type
		5'b11100 : imm_out = { 20'b0, instr_in[29:18] }; // CSR Addr

		default  : imm_out = 32'b0;
	endcase
end
endmodule